package com.jourwon.util.tree;

import org.apache.commons.collections4.CollectionUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * list列表构造tree树工具类
 *
 * @author JourWon
 * @since 2021/3/1
 */
public class TreeUtils {

    /**
     * 构造树列表
     * 根据数据库设计,如果父id为0或者null表示根节点
     *
     * @param treeVOList 树列表
     * @return List<T>
     */
    public static <T extends TreeNode> List<T> bulidTree(List<T> treeVOList) {
        List<T> resultList = new ArrayList<>();
        for (T treeVO : treeVOList) {
            // 根据数据库设计,如果父id为0或者null表示根节点
            if (treeVO.getParentId() == null || "0".equals(treeVO.getParentId())) {
                if (treeVO.getChildNodes() == null) {
                    treeVO.setChildNodes(new ArrayList<>());
                }
                // 构造树列表
                bulidChildTree(treeVOList, treeVO, treeVO.getChildNodes());
                // 设置树节点是否拥有子节点等属性
                setHasChildNode(treeVO);

                resultList.add(treeVO);
            }
        }

        return resultList;

    }

    /**
     * 构造树列表
     *
     * @param treeVOList       树列表
     * @param parentTreeVO     父节点
     * @param childrenNodeList 父节点的子树列表
     */
    public static <T extends TreeNode> void bulidChildTree(List<T> treeVOList, T parentTreeVO, List<TreeNode> childrenNodeList) {
        for (T treeVO : treeVOList) {
            if (parentTreeVO.getId().equals(treeVO.getParentId())) {
                if (treeVO.getChildNodes() == null) {
                    treeVO.setChildNodes(new ArrayList<>());
                }
                // 记录父节点
                treeVO.setParentTreeNode(parentTreeVO);
                // 构建子树
                bulidChildTree(treeVOList, treeVO, treeVO.getChildNodes());
                // 设置树节点是否拥有子节点等属性
                setHasChildNode(treeVO);

                childrenNodeList.add(treeVO);
            }
        }
    }

    /**
     * 设置树节点是否拥有子节点等属性
     *
     * @param treeNode 树对象
     */
    private static void setHasChildNode(TreeNode treeNode) {
        treeNode.setHasChildNode(null != treeNode.getChildNodes() && treeNode.getChildNodes().size() > 0);
    }

    /**
     * 设置树节点及其所有父节点的勾选状态
     *
     * @param treeVOList  树列表
     * @param checkedTree 需要勾选的树节点列表
     */
    public static <T extends TreeNode> void setTreeNodeChecked(List<T> treeVOList, List<String> checkedTree) {
        // 如果没有需要勾选的树节点,直接返回
        if (checkedTree == null || checkedTree.size() == 0) {
            return;
        }

        for (TreeNode treeNode : treeVOList) {
            // 如果当前节点在树已经勾选列表里面,设置当前节点为勾选状态
            if (checkedTree.contains(treeNode.getId())) {
                treeNode.setChecked(true);
            }
        }

        // 循环整棵树
        for (TreeNode treeNode : treeVOList) {
            // 如果当前节点已经被设置为勾选状态,那么就把它及其父节点都设置为勾选状态
            if (treeNode.getChecked() != null && treeNode.getChecked()) {
                TreeNode parentTreeNode = treeNode.getParentTreeNode();

                while (parentTreeNode != null
                        && (parentTreeNode.getChecked() == null || !parentTreeNode.getChecked())) {
                    parentTreeNode.setChecked(true);
                    parentTreeNode = parentTreeNode.getParentTreeNode();
                }
            }
        }
    }

    /**
     * 获取当前节点id及其子节点的id列表
     *
     * @param treeNodes 树化后的节点列表
     * @param id        节点id
     * @return List<TreeVO> 当前节点id及其子节点的树列表
     */
    public static List<String> listChildNodeIds(List<TreeNode> treeNodes, String id) {
        return listChildNodes(treeNodes, id).stream().map(TreeNode::getId).collect(Collectors.toList());
    }

    /**
     * 获取当前节点id及其子节点的树列表
     *
     * @param treeNodes 树化后的节点列表
     * @param id        节点id
     * @return List<TreeVO> 当前节点id及其子节点的树列表
     */
    public static List<TreeNode> listChildNodes(List<TreeNode> treeNodes, String id) {
        if (id == null || CollectionUtils.isEmpty(treeNodes)) {
            return null;
        }
        // 数据保存的对象
        List<TreeNode> result = new ArrayList<>();

        for (TreeNode t : treeNodes) {
            recursionTreeNode(t, id, result, t.getId());
        }

        return result;
    }

    private static void recursionTreeNode(TreeNode treeNode, String id, List<TreeNode> result, String treeId) {
        if (treeNode.getHasChildNode() && id.equals(treeId)) {
            result.add(treeNode);
            addChildNode(treeNode, result);
        } else {
            List<TreeNode> childNodes = treeNode.getChildNodes();
            if (CollectionUtils.isNotEmpty(childNodes)) {
                childNodes.forEach(node -> recursionTreeNode(node, id, result, node.getId()));
            }
        }
    }

    private static void addChildNode(TreeNode treeNode, List<TreeNode> result) {
        List<TreeNode> childNodes = treeNode.getChildNodes();
        if (CollectionUtils.isNotEmpty(childNodes)) {
            childNodes.forEach(node -> {
                result.add(node);
                addChildNode(node, result);
            });
        }
    }

    /**
     * 删除没有勾选的节点
     *
     * @param treeVOList 树列表
     * @param <T>        <T>
     */
    public static <T extends TreeNode> void removeTreeNode(List<T> treeVOList) {
        if (treeVOList == null) {
            return;
        }

        Iterator<T> treeVoIterator = treeVOList.iterator();

        while (treeVoIterator.hasNext()) {
            T treeVO = treeVoIterator.next();

            if (treeVO.getChecked() != null && treeVO.getChecked()) {
                removeTreeNode(treeVO.getChildNodes());
            } else {
                treeVoIterator.remove();
            }
        }
    }

}
